import sun.misc.VM;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.ProtectionDomain;

/**
 * questions:
 * 1. scale: 表示的是什么? 在ConcurrentHashMap中也使用了这个变量名.
 *  scale: 英文翻译过来是规模,比例，尺度. 这里我的理解是内存大小。
 *
 * @author fangjiaxiaobai@gmail.com
 * @date 2020-05-14
 * @since 1.0.0
 */
public final class Unsafe {

    /**
     * 私有对象
     */
    private static final Unsafe theUnsafe;
    public static final int INVALID_FIELD_OFFSET = -1;
    public static final int ARRAY_BOOLEAN_BASE_OFFSET;
    public static final int ARRAY_BYTE_BASE_OFFSET;
    public static final int ARRAY_SHORT_BASE_OFFSET;
    public static final int ARRAY_CHAR_BASE_OFFSET;
    public static final int ARRAY_INT_BASE_OFFSET;
    public static final int ARRAY_LONG_BASE_OFFSET;
    public static final int ARRAY_FLOAT_BASE_OFFSET;
    public static final int ARRAY_DOUBLE_BASE_OFFSET;
    public static final int ARRAY_OBJECT_BASE_OFFSET;
    public static final int ARRAY_BOOLEAN_INDEX_SCALE;
    public static final int ARRAY_BYTE_INDEX_SCALE;
    public static final int ARRAY_SHORT_INDEX_SCALE;
    public static final int ARRAY_CHAR_INDEX_SCALE;
    public static final int ARRAY_INT_INDEX_SCALE;
    public static final int ARRAY_LONG_INDEX_SCALE;
    public static final int ARRAY_FLOAT_INDEX_SCALE;
    public static final int ARRAY_DOUBLE_INDEX_SCALE;
    public static final int ARRAY_OBJECT_INDEX_SCALE;
    public static final int ADDRESS_SIZE;

    private static native void registerNatives();

    private Unsafe() {
    }

    @CallerSensitive
    public static Unsafe getUnsafe() {
        Class var0 = Reflection.getCallerClass();
        if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
            throw new SecurityException("Unsafe");
        } else {
            return theUnsafe;
        }
    }

    public native int getInt(Object var1, long var2);

    public native void putInt(Object var1, long var2, int var4);

    /**
     * 获取指定地址上的内容
     * <p>
     * getInt,getFloat,getDouble,getLong,getChar,getBoolean类似。
     * 这种访问方式会忽略修饰符。
     *
     * @param o      对象的起始地址
     * @param offset 偏移量
     * @return 地址值上的内容
     */
    public native Object getObject(Object o, long offset);

    /**
     * 给指定的内存地址上设置值。忽略修饰符。
     * <p>
     * putInt,putDouble,putLong,putChar,putBoolean类似
     *
     * @param o      对象
     * @param offset 偏移量
     * @param x      要设置的内容
     */
    public native void putObject(Object o, long offset, Object x);

    public native boolean getBoolean(Object var1, long var2);

    public native void putBoolean(Object var1, long var2, boolean var4);

    /**
     * 获取 给定地址上的值
     *
     * @param var1 对象(对象的首地址)
     * @param var2 偏移量
     * @return 返回对应地址上的值
     */
    public native byte getByte(Object var1, long var2);

    /***
     * 在指定的低智商设置值。
     * @param var1 对象
     * @param var2 偏移量
     * @param var4 新值
     */
    public native void putByte(Object var1, long var2, byte var4);

    public native short getShort(Object var1, long var2);

    public native void putShort(Object var1, long var2, short var4);

    public native char getChar(Object var1, long var2);

    public native void putChar(Object var1, long var2, char var4);

    public native long getLong(Object var1, long var2);

    public native void putLong(Object var1, long var2, long var4);

    public native float getFloat(Object var1, long var2);

    public native void putFloat(Object var1, long var2, float var4);

    public native double getDouble(Object var1, long var2);

    public native void putDouble(Object var1, long var2, double var4);

    /**
     * @deprecated
     */
    @Deprecated
    public int getInt(Object var1, int var2) {
        return this.getInt(var1, (long) var2);
    }

    /**
     * @deprecated
     */
    @Deprecated
    public void putInt(Object var1, int var2, int var3) {
        this.putInt(var1, (long) var2, var3);
    }

    /**
     * @deprecated
     */
    @Deprecated
    public Object getObject(Object var1, int var2) {
        return this.getObject(var1, (long) var2);
    }

    /**
     * @deprecated
     */
    @Deprecated
    public void putObject(Object var1, int var2, Object var3) {
        this.putObject(var1, (long) var2, var3);
    }

    /**
     * @deprecated
     */
    @Deprecated
    public boolean getBoolean(Object var1, int var2) {
        return this.getBoolean(var1, (long) var2);
    }

    /**
     * @deprecated
     */
    @Deprecated
    public void putBoolean(Object var1, int var2, boolean var3) {
        this.putBoolean(var1, (long) var2, var3);
    }

    /**
     * @deprecated
     */
    @Deprecated
    public byte getByte(Object var1, int var2) {
        return this.getByte(var1, (long) var2);
    }

    /**
     * @deprecated
     */
    @Deprecated
    public void putByte(Object var1, int var2, byte var3) {
        this.putByte(var1, (long) var2, var3);
    }

    /**
     * @deprecated
     */
    @Deprecated
    public short getShort(Object var1, int var2) {
        return this.getShort(var1, (long) var2);
    }

    /**
     * @deprecated
     */
    @Deprecated
    public void putShort(Object var1, int var2, short var3) {
        this.putShort(var1, (long) var2, var3);
    }

    /**
     * @deprecated
     */
    @Deprecated
    public char getChar(Object var1, int var2) {
        return this.getChar(var1, (long) var2);
    }

    /**
     * @deprecated
     */
    @Deprecated
    public void putChar(Object var1, int var2, char var3) {
        this.putChar(var1, (long) var2, var3);
    }

    /**
     * @deprecated
     */
    @Deprecated
    public long getLong(Object var1, int var2) {
        return this.getLong(var1, (long) var2);
    }

    /**
     * @deprecated
     */
    @Deprecated
    public void putLong(Object var1, int var2, long var3) {
        this.putLong(var1, (long) var2, var3);
    }

    /**
     * @deprecated
     */
    @Deprecated
    public float getFloat(Object var1, int var2) {
        return this.getFloat(var1, (long) var2);
    }

    /**
     * @deprecated
     */
    @Deprecated
    public void putFloat(Object var1, int var2, float var3) {
        this.putFloat(var1, (long) var2, var3);
    }

    /**
     * @deprecated
     */
    @Deprecated
    public double getDouble(Object var1, int var2) {
        return this.getDouble(var1, (long) var2);
    }

    /**
     * @deprecated
     */
    @Deprecated
    public void putDouble(Object var1, int var2, double var3) {
        this.putDouble(var1, (long) var2, var3);
    }

    public native byte getByte(long var1);

    public native void putByte(long var1, byte var3);

    public native short getShort(long var1);

    public native void putShort(long var1, short var3);

    public native char getChar(long var1);

    public native void putChar(long var1, char var3);

    public native int getInt(long var1);

    public native void putInt(long var1, int var3);

    public native long getLong(long var1);

    public native void putLong(long var1, long var3);

    public native float getFloat(long var1);

    public native void putFloat(long var1, float var3);

    public native double getDouble(long var1);

    public native void putDouble(long var1, double var3);

    public native long getAddress(long var1);

    public native void putAddress(long var1, long var3);

    /**
     * 分配内存 相当于与 malloc 函数
     *
     * @param bytes ??
     * @return ??
     */
    public native long allocateMemory(long bytes);

    /**
     * 重新分配内存
     *
     * @param address 地址
     * @param bytes 字节数
     * @return ??
     */
    public native long reallocateMemory(long address, long bytes);

    /**
     * 在指定的内存地址上设置值
     *
     * @param o 对象
     * @param offset 偏移量
     * @param bytes 字节
     * @param value 值
     */
    public native void setMemory(Object o, long offset, long bytes, byte value);

    public void setMemory(long var1, long var3, byte var5) {
        this.setMemory((Object) null, var1, var3, var5);
    }

    /**
     * 拷贝内存
     *
     * @param var1 ??
     * @param var2 ??
     * @param var4 ??
     * @param var5 ??
     * @param var7 ??
     */
    public native void copyMemory(Object var1, long var2, Object var4, long var5, long var7);

    public void copyMemory(long var1, long var3, long var5) {
        this.copyMemory((Object) null, var1, (Object) null, var3, var5);
    }

    /**
     * 释放指定内存
     *
     * @param var1 内存地址
     */
    public native void freeMemory(long var1);

    /**
     * @deprecated
     */
    @Deprecated
    public int fieldOffset(Field var1) {
        return Modifier.isStatic(var1.getModifiers()) ? (int) this.staticFieldOffset(var1) :
                (int) this.objectFieldOffset(var1);
    }

    /**
     * @deprecated
     */
    @Deprecated
    public Object staticFieldBase(Class<?> var1) {
        Field[] var2 = var1.getDeclaredFields();

        for (int var3 = 0; var3 < var2.length; ++var3) {
            if (Modifier.isStatic(var2[var3].getModifiers())) {
                return this.staticFieldBase(var2[var3]);
            }
        }

        return null;
    }

    /**
     * 获取给定静态字段的内存地址偏移量, 这个值对于给定的字段是唯一且固定不变的。
     *
     * @param f 字段
     * @return 偏移地址
     */
    public native long staticFieldOffset(Field f);

    /**
     * 返回对象成员属性在内存地址相对于此对象的内存地址的偏移量。
     *
     * @param f 成员属性
     * @return 偏移量
     */
    public native long objectFieldOffset(Field f);

    /**
     * 获取一个静态类中给定字段的对象指针
     *
     * @param f 字段
     * @return 对象指针
     */
    public native Object staticFieldBase(Field f);

    /**
     * 判断是否要初始化一个类
     * <p>
     * 通常在获取一个类的静态属性的时候（因为一个类如果没初始化，它的静态属性也不会初始化）使用。
     * 当且仅当ensureClassInitialized方法不生效时返回false。
     *
     * @param c 待判断的类
     * @return boolean
     */
    public native boolean shouldBeInitialized(Class<?> c);

    /**
     * 检测给定的类是否已经初始化。
     * 通常在获取一个类的静态属性的时候（因为一个类如果没初始化，它的静态属性也不会初始化）使用。
     *
     * @param c 待判断的类
     */
    public native void ensureClassInitialized(Class<?> c);

    /**
     * 返回数组中第一个元素的偏移地址
     *
     * @param arrayClass 数组类型
     * @return 偏移地址
     */
    public native int arrayBaseOffset(Class<?> arrayClass);

    /**
     * 返回数组中一个元素占用的大小
     *
     * @param arrayClass 数组类型
     * @return 占用空间大小
     */
    public native int arrayIndexScale(Class<?> arrayClass);

    /**
     * 返回系统指针的大小。返回值为4（32位系统）或 8（64位系统）。
     * @return 系统指针的大小
     */
    public native int addressSize();

    /**
     * 内存页的大小，此值为2的幂次方
     * @return 内存页的大小
     */
    public native int pageSize();

    /**
     * 定义一个类，此方法会跳过JVM的所有安全检查，
     * 默认情况下，ClassLoader（类加载器）和ProtectionDomain（保护域）实例来源于调用者
     *
     * @param name             类名称
     * @param b                字节
     * @param off              偏移量
     * @param len              长度
     * @param loader           类加载器
     * @param protectionDomain 保护欲
     * @return 类型
     */
    public native Class<?> defineClass(String name, byte[] b, int off, int len, ClassLoader loader,
                                       ProtectionDomain protectionDomain);

    /**
     * 创建一个匿名类
     *
     * @param hostClass ??
     * @param data      类数据
     * @param cpPatches ??
     * @return 匿名类
     */
    public native Class<?> defineAnonymousClass(Class<?> hostClass, byte[] data, Object[] cpPatches);

    /**
     * 绕过构造方法、初始化代码来创建对象
     *
     * @param cls 类型
     * @return 对象
     * @throws InstantiationException 异常
     */
    public native Object allocateInstance(Class<?> cls) throws InstantiationException;

    /**
     * 获得对象锁(可重入锁)
     *
     * @param o 对象
     */
    @Deprecated
    public native void monitorEnter(Object o);

    /**
     * 释放对象锁
     *
     * @param o 对象
     */
    @Deprecated
    public native void monitorExit(Object o);

    /**
     * 尝试获取对象的锁(可重入锁)
     *
     * @param o 对象
     * @return 是否获取成功
     */
    @Deprecated
    public native boolean tryMonitorEnter(Object o);

    public native void throwException(Throwable var1);

    /**
     * CAS 对象
     *
     * @param o        原对象
     * @param offset   偏移量
     * @param expected 预期值
     * @param update   更新值
     * @return boolean
     */
    public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object update);

    public final native boolean compareAndSwapInt(Object o, long offset, int expected, int update);

    public final native boolean compareAndSwapLong(Object o, long offset, long expected, long update);

    /**
     * 从对象的指定偏移量处获取变量的引用，使用volatile的加载语义
     *
     * @param o      对象
     * @param offset 偏移量
     * @return 值
     */
    public native Object getObjectVolatile(Object o, long offset);

    /**
     * 存储变量的引用到对象的指定的偏移量处，使用volatile的存储语义
     *
     * @param o      对象
     * @param offset 偏移量
     * @param x      新对象
     */
    public native void putObjectVolatile(Object o, long offset, Object x);

    public native int getIntVolatile(Object var1, long var2);

    public native void putIntVolatile(Object var1, long var2, int var4);

    public native boolean getBooleanVolatile(Object var1, long var2);

    public native void putBooleanVolatile(Object var1, long var2, boolean var4);

    public native byte getByteVolatile(Object var1, long var2);

    public native void putByteVolatile(Object var1, long var2, byte var4);

    public native short getShortVolatile(Object var1, long var2);

    public native void putShortVolatile(Object var1, long var2, short var4);

    public native char getCharVolatile(Object var1, long var2);

    public native void putCharVolatile(Object var1, long var2, char var4);

    public native long getLongVolatile(Object var1, long var2);

    public native void putLongVolatile(Object var1, long var2, long var4);

    public native float getFloatVolatile(Object var1, long var2);

    public native void putFloatVolatile(Object var1, long var2, float var4);

    public native double getDoubleVolatile(Object var1, long var2);

    public native void putDoubleVolatile(Object var1, long var2, double var4);

    /**
     * 有序、延迟版本的putObjectVolatile方法，
     * 不保证值的改变被其他线程立即看到。只有在field被volatile修饰符修饰时有效
     *
     * @param o      对象
     * @param offset 偏移量
     * @param x      新对象
     */
    public native void putOrderedObject(Object o, long offset, Object x);

    public native void putOrderedInt(Object var1, long var2, int var4);

    public native void putOrderedLong(Object var1, long var2, long var4);

    /**
     * 取消阻塞线程
     *
     * @param thread 线程
     */
    public native void unpark(Object thread);

    /**
     * 阻塞线程
     *
     * @param isAbsolute 是否是绝对的??
     * @param time       阻塞时长
     */
    public native void park(boolean isAbsolute, long time);

    public native int getLoadAverage(double[] var1, int var2);

    public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while (!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }

    public final long getAndAddLong(Object var1, long var2, long var4) {
        long var6;
        do {
            var6 = this.getLongVolatile(var1, var2);
        } while (!this.compareAndSwapLong(var1, var2, var6, var6 + var4));

        return var6;
    }

    public final int getAndSetInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while (!this.compareAndSwapInt(var1, var2, var5, var4));

        return var5;
    }

    public final long getAndSetLong(Object var1, long var2, long var4) {
        long var6;
        do {
            var6 = this.getLongVolatile(var1, var2);
        } while (!this.compareAndSwapLong(var1, var2, var6, var4));

        return var6;
    }

    public final Object getAndSetObject(Object var1, long var2, Object var4) {
        Object var5;
        do {
            var5 = this.getObjectVolatile(var1, var2);
        } while (!this.compareAndSwapObject(var1, var2, var5, var4));

        return var5;
    }

    /**
     * 内存屏障，禁止load操作重排序。
     * 屏障前的load操作不能被重排序到屏障后，屏障后的load操作不能被重排序到屏障前
     */
    public native void loadFence();

    /**
     * 内存屏障，禁止store操作重排序。
     * 屏障前的store操作不能被重排序到屏障后，屏障后的store操作不能被重排序到屏障前
     */
    public native void storeFence();

    /**
     * 内存屏障，禁止load、store操作重排序
     */
    public native void fullFence();

    private static void throwIllegalAccessError() {
        throw new IllegalAccessError();
    }

    static {
        registerNatives();
        Reflection.registerMethodsToFilter(sun.misc.Unsafe.class, new String[]{"getUnsafe"});
        theUnsafe = new Unsafe();
        ARRAY_BOOLEAN_BASE_OFFSET = theUnsafe.arrayBaseOffset(boolean[].class);
        ARRAY_BYTE_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class);
        ARRAY_SHORT_BASE_OFFSET = theUnsafe.arrayBaseOffset(short[].class);
        ARRAY_CHAR_BASE_OFFSET = theUnsafe.arrayBaseOffset(char[].class);
        ARRAY_INT_BASE_OFFSET = theUnsafe.arrayBaseOffset(int[].class);
        ARRAY_LONG_BASE_OFFSET = theUnsafe.arrayBaseOffset(long[].class);
        ARRAY_FLOAT_BASE_OFFSET = theUnsafe.arrayBaseOffset(float[].class);
        ARRAY_DOUBLE_BASE_OFFSET = theUnsafe.arrayBaseOffset(double[].class);
        ARRAY_OBJECT_BASE_OFFSET = theUnsafe.arrayBaseOffset(Object[].class);
        ARRAY_BOOLEAN_INDEX_SCALE = theUnsafe.arrayIndexScale(boolean[].class);
        ARRAY_BYTE_INDEX_SCALE = theUnsafe.arrayIndexScale(byte[].class);
        ARRAY_SHORT_INDEX_SCALE = theUnsafe.arrayIndexScale(short[].class);
        ARRAY_CHAR_INDEX_SCALE = theUnsafe.arrayIndexScale(char[].class);
        ARRAY_INT_INDEX_SCALE = theUnsafe.arrayIndexScale(int[].class);
        ARRAY_LONG_INDEX_SCALE = theUnsafe.arrayIndexScale(long[].class);
        ARRAY_FLOAT_INDEX_SCALE = theUnsafe.arrayIndexScale(float[].class);
        ARRAY_DOUBLE_INDEX_SCALE = theUnsafe.arrayIndexScale(double[].class);
        ARRAY_OBJECT_INDEX_SCALE = theUnsafe.arrayIndexScale(Object[].class);
        ADDRESS_SIZE = theUnsafe.addressSize();
    }
}

